home *** CD-ROM | disk | FTP | other *** search
- /* move1.c */
-
- /* Author:
- * Steve Kirkendall
- * 14407 SW Teal Blvd. #C
- * Beaverton, OR 97005
- * kirkenda@cs.pdx.edu
- */
-
-
- /* This file contains most movement functions */
-
- #include "config.h"
- #include "vi.h"
- #include "ctype.h"
-
- MARK m_updnto(m, cnt, cmd)
- MARK m; /* movement is relative to this mark */
- long cnt; /* a numeric argument */
- char cmd; /* the command character */
- {
- DEFAULT(cmd == 'G' ? nlines : 1L);
-
- /* move up or down 'cnt' lines */
- switch (cmd)
- {
- case ctrl('P'):
- case '-':
- case 'k':
- m -= MARK_AT_LINE(cnt);
- break;
-
- case 'G':
- if (cnt < 1L || cnt > nlines)
- {
- msg("Only %ld lines", nlines);
- return MARK_UNSET;
- }
- m = MARK_AT_LINE(cnt);
- break;
-
- case '_':
- cnt--;
- /* fall through... */
-
- default:
- m += MARK_AT_LINE(cnt);
- }
-
- /* if that left us screwed up, then fail */
- if (m < MARK_FIRST || markline(m) > nlines)
- {
- return MARK_UNSET;
- }
-
- return m;
- }
-
- /*ARGSUSED*/
- MARK m_right(m, cnt, key, prevkey)
- MARK m; /* movement is relative to this mark */
- long cnt; /* a numeric argument */
- int key; /* movement keystroke */
- int prevkey;/* operator keystroke, or 0 if none */
- {
- int idx; /* index of the new cursor position */
-
- DEFAULT(1);
-
- /* If used with an operator, then move 1 less character, since the 'l'
- * command includes the character that it moves onto.
- */
- if (prevkey != '\0')
- {
- cnt--;
- }
-
- /* move to right, if that's OK */
- pfetch(markline(m));
- idx = markidx(m) + cnt;
- if (idx < plen)
- {
- m += cnt;
- }
- else
- {
- return MARK_UNSET;
- }
-
- return m;
- }
-
- /*ARGSUSED*/
- MARK m_left(m, cnt)
- MARK m; /* movement is relative to this mark */
- long cnt; /* a numeric argument */
- {
- DEFAULT(1);
-
- /* move to the left, if that's OK */
- if (markidx(m) >= cnt)
- {
- m -= cnt;
- }
- else
- {
- return MARK_UNSET;
- }
-
- return m;
- }
-
- /*ARGSUSED*/
- MARK m_tocol(m, cnt, cmd)
- MARK m; /* movement is relative to this mark */
- long cnt; /* a numeric argument */
- int cmd; /* either ctrl('X') or '|' */
- {
- char *text; /* text of the line */
- int col; /* column number */
- int idx; /* index into the line */
-
-
- /* if doing ^X, then adjust for sideways scrolling */
- if (cmd == ctrl('X'))
- {
- DEFAULT(*o_columns & 0xff);
- cnt += leftcol;
- }
- else
- {
- DEFAULT(1);
- }
-
- /* internally, columns are numbered 0..COLS-1, not 1..COLS */
- cnt--;
-
- /* if 0, that's easy */
- if (cnt == 0)
- {
- m &= ~(BLKSIZE - 1);
- return m;
- }
-
- /* find that column within the line */
- pfetch(markline(m));
- text = ptext;
- for (col = idx = 0; col < cnt && *text; text++, idx++)
- {
- if (*text == '\t' && !*o_list)
- {
- col += *o_tabstop;
- col -= col % *o_tabstop;
- }
- else if (UCHAR(*text) < ' ' || *text == '\177')
- {
- col += 2;
- }
- #ifndef NO_CHARATTR
- else if (text[0] == '\\' && text[1] == 'f' && text[2] && *o_charattr)
- {
- text += 2; /* plus one more as part of for loop */
- }
- #endif
- else
- {
- col++;
- }
- }
- if (!*text)
- {
- /* the desired column was past the end of the line, so
- * act like the user pressed "$" instead.
- */
- return m | (BLKSIZE - 1);
- }
- else
- {
- m = (m & ~(BLKSIZE - 1)) + idx;
- }
- return m;
- }
-
- /*ARGSUSED*/
- MARK m_front(m, cnt)
- MARK m; /* movement is relative to this mark */
- long cnt; /* a numeric argument (ignored) */
- {
- char *scan;
-
- /* move to the first non-whitespace character */
- pfetch(markline(m));
- scan = ptext;
- m &= ~(BLKSIZE - 1);
- while (*scan == ' ' || *scan == '\t')
- {
- scan++;
- m++;
- }
-
- return m;
- }
-
- /*ARGSUSED*/
- MARK m_rear(m, cnt)
- MARK m; /* movement is relative to this mark */
- long cnt; /* a numeric argument (ignored) */
- {
- /* Try to move *EXTREMELY* far to the right. It is fervently hoped
- * that other code will convert this to a more reasonable MARK before
- * anything tries to actually use it. (See adjmove() in vi.c)
- */
- return m | (BLKSIZE - 1);
- }
-
- #ifndef NO_SENTENCE
- static int isperiod(ptr)
- char *ptr; /* pointer to possible sentence-ender */
- {
- /* if not '.', '?', or '!', then it isn't a sentence ender */
- if (*ptr != '.' && *ptr != '?' && *ptr != '!')
- {
- return FALSE;
- }
-
- /* skip any intervening ')', ']', or '"' characters */
- do
- {
- ptr++;
- } while (*ptr == ')' || *ptr == ']' || *ptr == '"');
-
- /* do we have two spaces or EOL? */
- if (!*ptr || ptr[0] == ' ' && ptr[1] == ' ')
- {
- return TRUE;
- }
- return FALSE;
- }
-
- /*ARGSUSED*/
- MARK m_sentence(m, cnt, cmd)
- MARK m; /* movement is relative to this mark */
- long cnt; /* a numeric argument */
- int cmd; /* either '(' or ')' */
- {
- REG char *text;
- REG long l;
-
- DEFAULT(1);
-
- /* If '(' command, then move back one word, so that if we hit '(' at
- * the start of a sentence we don't simply stop at the end of the
- * previous sentence and bounce back to the start of this one again.
- */
- if (cmd == '(')
- {
- m = m_bword(m, 1L, 'b');
- if (!m)
- {
- return m;
- }
- }
-
- /* get the current line */
- l = markline(m);
- pfetch(l);
- text = ptext + markidx(m);
-
- /* for each requested sentence... */
- while (cnt-- > 0)
- {
- /* search forward for one of [.?!] followed by spaces or EOL */
- do
- {
- if (cmd == ')')
- {
- /* move forward, wrap at end of line */
- if (!text[0])
- {
- if (l >= nlines)
- {
- return MARK_UNSET;
- }
- l++;
- pfetch(l);
- text = ptext;
- }
- else
- {
- text++;
- }
- }
- else
- {
- /* move backward, wrap at beginning of line */
- if (text == ptext)
- {
- do
- {
- if (l <= 1)
- {
- return MARK_FIRST;
- }
- l--;
- pfetch(l);
- } while (!*ptext);
- text = ptext + plen - 1;
- }
- else
- {
- text--;
- }
- }
- } while (!isperiod(text));
- }
-
- /* construct a mark for this location */
- m = buildmark(text);
-
- /* move forward to the first word of the next sentence */
- m = m_fword(m, 1L, 'w', '\0');
-
- return m;
- }
- #endif
-
- MARK m_paragraph(m, cnt, cmd)
- MARK m; /* movement is relative to this mark */
- long cnt; /* a numeric argument */
- int cmd; /* either '{' or '}' */
- {
- char *text; /* text of the current line */
- char *pscn; /* used to scan thru value of "paragraphs" option */
- long l, ol; /* current line number, original line number */
- int dir; /* -1 if we're moving up, or 1 if down */
- char col0; /* character to expect in column 0 */
- #ifndef NO_SENTENCE
- # define SENTENCE(x) (x)
- char *list; /* either o_sections or o_paragraph */
- #else
- # define SENTENCE(x)
- #endif
-
- DEFAULT(1);
-
- /* set the direction, based on the command */
- switch (cmd)
- {
- case '{':
- dir = -1;
- col0 = '\0';
- SENTENCE(list = o_paragraphs);
- break;
-
- case '}':
- dir = 1;
- col0 = '\0';
- SENTENCE(list = o_paragraphs);
- break;
-
- case '[':
- if (getkey(0) != '[')
- {
- return MARK_UNSET;
- }
- dir = -1;
- col0 = '{';
- SENTENCE(list = o_sections);
- break;
-
- case ']':
- if (getkey(0) != ']')
- {
- return MARK_UNSET;
- }
- dir = 1;
- col0 = '{';
- SENTENCE(list = o_sections);
- break;
- }
- ol = l = markline(m);
-
- /* for each paragraph that we want to travel through... */
- while (l > 0 && l <= nlines && cnt-- > 0)
- {
- /* skip blank lines between paragraphs */
- while (l > 0 && l <= nlines && col0 == *(text = fetchline(l)))
- {
- l += dir;
- }
-
- /* skip non-blank lines that aren't paragraph separators
- */
- do
- {
- #ifndef NO_SENTENCE
- if (*text == '.' && l != ol)
- {
- for (pscn = list; pscn[0] && pscn[1]; pscn += 2)
- {
- if (pscn[0] == text[1] && pscn[1] == text[2])
- {
- pscn = (char *)0;
- goto BreakBreak;
- }
- }
- }
- #endif
- l += dir;
- } while (l > 0 && l <= nlines && col0 != *(text = fetchline(l)));
- BreakBreak: ;
- }
-
- if (l > nlines)
- {
- m = MARK_LAST;
- }
- else if (l <= 0)
- {
- m = MARK_FIRST;
- }
- else
- {
- m = MARK_AT_LINE(l);
- }
- return m;
- }
-
-
- /*ARGSUSED*/
- MARK m_match(m, cnt)
- MARK m; /* movement is relative to this mark */
- long cnt; /* a numeric argument (normally 0) */
- {
- long l;
- REG char *text;
- REG char match;
- REG char nest;
- REG int count;
-
- #ifndef NO_EXTENSIONS
- /* if we're given a number, then treat it as a percentage of the file */
- if (cnt > 0)
- {
- /* make sure it is a reasonable number */
- if (cnt > 100)
- {
- msg("can only be from 1%% to 100%%");
- return MARK_UNSET;
- }
-
- /* return the appropriate line number */
- l = (nlines - 1L) * cnt / 100L + 1L;
- return MARK_AT_LINE(l);
- }
- #endif /* undef NO_EXTENSIONS */
-
- /* get the current line */
- l = markline(m);
- pfetch(l);
- text = ptext + markidx(m);
-
- /* search forward within line for one of "[](){}" */
- for (match = '\0'; !match && *text; text++)
- {
- /* tricky way to recognize 'em in ASCII */
- nest = *text;
- if ((nest & 0xdf) == ']' || (nest & 0xdf) == '[')
- {
- match = nest ^ ('[' ^ ']');
- }
- else if ((nest & 0xfe) == '(')
- {
- match = nest ^ ('(' ^ ')');
- }
- else
- {
- match = 0;
- }
- }
- if (!match)
- {
- return MARK_UNSET;
- }
- text--;
-
- /* search forward or backward for match */
- if (match == '(' || match == '[' || match == '{')
- {
- /* search backward */
- for (count = 1; count > 0; )
- {
- /* wrap at beginning of line */
- if (text == ptext)
- {
- do
- {
- if (l <= 1L)
- {
- return MARK_UNSET;
- }
- l--;
- pfetch(l);
- } while (!*ptext);
- text = ptext + plen - 1;
- }
- else
- {
- text--;
- }
-
- /* check the char */
- if (*text == match)
- count--;
- else if (*text == nest)
- count++;
- }
- }
- else
- {
- /* search forward */
- for (count = 1; count > 0; )
- {
- /* wrap at end of line */
- if (!*text)
- {
- if (l >= nlines)
- {
- return MARK_UNSET;
- }
- l++;
- pfetch(l);
- text = ptext;
- }
- else
- {
- text++;
- }
-
- /* check the char */
- if (*text == match)
- count--;
- else if (*text == nest)
- count++;
- }
- }
-
- /* construct a mark for this place */
- m = buildmark(text);
- return m;
- }
-
- /*ARGSUSED*/
- MARK m_tomark(m, cnt, key)
- MARK m; /* movement is relative to this mark */
- long cnt; /* (ignored) */
- int key; /* keystroke - the mark to move to */
- {
- /* mark '' is a special case */
- if (key == '\'' || key == '`')
- {
- if (mark[26] == MARK_UNSET)
- {
- return MARK_FIRST;
- }
- else
- {
- return mark[26];
- }
- }
-
- /* if not a valid mark number, don't move */
- if (key < 'a' || key > 'z')
- {
- return MARK_UNSET;
- }
-
- /* return the selected mark -- may be MARK_UNSET */
- if (!mark[key - 'a'])
- {
- msg("mark '%c is unset", key);
- }
- return mark[key - 'a'];
- }
-
-